﻿#define _CRT_SECURE_NO_WARNINGS
#define HAVE_REMOTE
#define WIN32

#include <pcap.h>
#include <Packet32.h>
#include <ntddndis.h>
#include <string.h>
#pragma comment(lib, "Packet")
#pragma comment(lib, "wpcap")
#pragma comment(lib, "WS2_32")

typedef struct ip_header {
    u_char ver_ihl;
    u_char tos;
    u_short tlen;
    u_short identification;
    u_short flags_fo;
    u_char ttl;
    u_char proto;
    u_short crc;
    u_char saddr[4];
    u_char daddr[4];
    u_int op_pad;
} ip_header;

typedef struct mac_header {
    u_char dest_addr[6];
    u_char src_addr[6];
    u_char type[2];
} mac_header;

void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);

int main() {
    int inum;
    pcap_if_t* alldevs;
    pcap_if_t* d;
    char errbuf[PCAP_ERRBUF_SIZE];
    char source[PCAP_ERRBUF_SIZE];
    pcap_t* adhandle;
    int i = 0;
    struct pcap_pkthdr* pkt_header;
    const u_char* pkt_data;
    int res;
    u_int netmask;
    char packet_filter[] = "ip and udp";
    struct bpf_program fcode;
    ip_header* ih;
    u_int ip_len;
    u_short sport, dport;

    if (pcap_findalldevs_ex((char*)PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
        fprintf(stderr, "在获取网络设备列表时出错: %s\n", errbuf);
        exit(1);
    }

    for (d = alldevs; d; d = d->next) {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (无可用描述信息)\n");
    }

    if (i == 0) {
        printf("\n未找到可用的网络接口！请确保已安装WinPcap。\n");
        return -1;
    }

    printf("请输入要使用的网络接口编号 (1-%d):", i);
    scanf("%d", &inum);
    if (inum < 1 || inum > i) {
        printf("\n输入的接口编号超出范围。\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);

    if ((adhandle = pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf)) == NULL) {
        fprintf(stderr, "\n无法打开网络适配器。%s 不被WinPcap支持。\n", d->name);
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (pcap_datalink(adhandle) != DLT_EN10MB) {
        fprintf(stderr, "\n此程序仅适用于以太网网络。\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (d->addresses != NULL)
        netmask = ((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        netmask = 0xffffff;

    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0) {
        fprintf(stderr, "\n无法编译数据包过滤器。请检查语法。\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (pcap_setfilter(adhandle, &fcode) < 0) {
        fprintf(stderr, "\n设置过滤器时出错。\n");
        pcap_freealldevs(alldevs);
        return -1;
    }

    printf("\n正在监听 %s...\n", d->description);
    pcap_freealldevs(alldevs);
    pcap_loop(adhandle, 0, packet_handler, NULL);

    return 0;
}

void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data) {
    struct tm* ltime;
    mac_header* mh;
    char timestr[16];
    ip_header* ih;
    time_t local_tv_sec;

    local_tv_sec = header->ts.tv_sec;
    ltime = localtime(&local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);

    mh = (mac_header*)pkt_data;
    ih = (ip_header*)(pkt_data + sizeof(mac_header));

    if (mh->type[1] == 0 && mh->type[0] == 8) {
        printf("捕获到一个IP数据包\n");
        if (ih->proto == 0x0001)
            printf("捕获到一个ICMP数据包\n");
    }
    else if (mh->type[1] == 6 && mh->type[0] == 8)
        printf("捕获到一个ARP数据包\n");

    printf("以太网帧头部信息:\n");
    printf("\t目的MAC地址: ");
    for (int i = 0; i < 6; i++) {
        if (i != 5)
            printf("%02x:", mh->dest_addr[i]);
        else
            printf("%02x\n", mh->dest_addr[i]);
    }
    printf("\t源MAC地址: ");
    for (int i = 0; i < 6; i++) {
        if (i != 5)
            printf("%02x:", mh->src_addr[i]);
        else
            printf("%02x\n", mh->src_addr[i]);
    }
    printf("\t协议类型: %04X\n", ntohs((u_short)mh->type));

    printf("IP头部信息\n");
    printf("\t版本与首部长度: %02X\n", ih->ver_ihl);
    printf("\t服务类型: %02X\n", ih->tos);
    printf("\t总长度: %04X\n", ntohs(ih->tlen));
    printf("\t标识: %04X\n", ntohs(ih->identification));
    printf("\t标志与片偏移: %04X\n", ntohs(ih->flags_fo));
    printf("\t生存时间: %02X\n", ih->ttl);
    printf("\t协议: %02X\n", ih->proto);
    printf("\t首部校验和: %04X\n", ntohs(ih->crc));
    printf("\t选项与填充: %08X\n", ntohs(ih->op_pad));
    printf("\t源IP地址: ");
    for (int i = 0; i < 4; i++) {
        if (i != 3)
            printf("%d.", ih->saddr[i]);
        else
            printf("%d\n", ih->saddr[i]);
    }
    printf("\t目的IP地址: ");
    for (int i = 0; i < 4; i++) {
        if (i != 3)
            printf("%d.", ih->daddr[i]);
        else
            printf("%d\n", ih->daddr[i]);
    }
    printf("\n");

    FILE* fp = fopen("data.csv", "a+");
    printf("开始写入文件\n");
    fprintf(fp, "捕获到一个数据包\n");
    fprintf(fp, "时间,%s\n", timestr);
    fprintf(fp, "源MAC地址,");
    for (int i = 0; i < 6; i++) {
        if (i != 5)
            fprintf(fp, "%02x:", mh->src_addr[i]);
        else
            fprintf(fp, "%02x\n", mh->src_addr[i]);
    }
    fprintf(fp, "目的MAC地址,");
    for (int i = 0; i < 6; i++) {
        if (i != 5)
            fprintf(fp, "%02x:", mh->dest_addr[i]);
        else
            fprintf(fp, "%02x\n", mh->dest_addr[i]);
    }
    fprintf(fp, "源IP地址,");
    for (int i = 0; i < 4; i++) {
        if (i != 3)
            fprintf(fp, "%d.", ih->saddr[i]);
        else
            fprintf(fp, "%d\n", ih->saddr[i]);
    }
    fprintf(fp, "目的IP地址,");
    for (int i = 0; i < 4; i++) {
        if (i != 3)
            fprintf(fp, "%d.", ih->daddr[i]);
        else
            fprintf(fp, "%d\n", ih->daddr[i]);
    }
    fprintf(fp, "帧长度,%d\n\n", header->len);

    fclose(fp);
}